home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / lang / c-part1 / 629 < prev    next >
Encoding:
Internet Message Format  |  1996-08-05  |  6.0 KB

  1. Path: Rezonet.net!news
  2. From: ray@ultimate-tech.com (Ray Dunn)
  3. Newsgroups: comp.lang.c
  4. Subject: Re: my atoi function, could someone suggest...
  5. Date: 8 Jan 1996 05:12:06 GMT
  6. Organization: Ultimate Technographics Inc.
  7. Message-ID: <4cq937$if9@ns.RezoNet.NET>
  8. References: <4cf7ap$q4u@kaleka.seanet.com>
  9. NNTP-Posting-Host: 204.19.230.7
  10. Mime-Version: 1.0
  11. Content-Type: Text/Plain; charset=US-ASCII
  12. X-Newsreader: WinVN 0.99.7
  13.  
  14. In referenced article, where am i? says...
  15. >Hello.  This is my first attempt at an atoi function.  Although it
  16. >works and behaves just like atoi, I was wondering if anyone would care
  17. >for a look and make suggestions back to me about its efficiency.
  18. >
  19. >int atoi ( char *change )
  20. >{
  21. >    int newint = 0, sign = 1;
  22. >
  23. >    while ( *change )
  24. >    {
  25. >            if ( (*change < '0' || *change > '9') && *change != '-' )
  26. >            {
  27. >                    *change++;
  28. >            }
  29. >            else
  30. >            {
  31. >                    if ( *change == '-' )
  32. >                    {
  33. >                            *change++;
  34. >                            if ( *change >= '0' && *change <= '9' )
  35. >                                    sign = -1;
  36. >                    }
  37. >                    if ( *change >= '0' && *change <= '9' )
  38. >                    {
  39. >                            while ( sign )
  40. >                            {
  41. >                                    newint *= 10;
  42. >                                    newint = newint + *change - 48;
  43. >                                    *change++;
  44. >                                    if ( *change < '0' || *change > 
  45. '9')
  46. >                                    {
  47. >                                            return (  newint * sign );
  48. >                                            exit (0);
  49. >                                    }
  50. >                            }
  51. >                    }
  52. >            }
  53. >    }
  54. >    return ( 0 );
  55. >}
  56.  
  57. This only behaves like the "real" atoi in a limited number of cases.
  58.  
  59. atoi allows the number to be preceded by any whitespace character.
  60.  
  61. It returns 0 if the first character met after the whitespace is not a 
  62. digit or a sign, or if the first character after a sign is not a digit.
  63.  
  64. It also allows '+' as well as '-' for the sign 
  65.  
  66. In your code, all occurrences of "*change++;" should be "change++;".
  67.  
  68. Your use of "48" is opaque, you should use "'0'".
  69.  
  70. Your use of "exit(0);" after "return(0);" is unneccessary, and you 
  71. don't want to exit here under any circumstances anyway, so the line 
  72. should be removed.
  73.  
  74. Your use of "while (sign)" is bizarre.  "sign" is *always* non-zero, 
  75. and thus always true, and although you may want such a loop here, it 
  76. doesn't show your intent.
  77.  
  78. Your encompasing "while (*change)" block *looks* as if its driving the 
  79. whole scan, but in fact it only drives the initial scan for a sign or 
  80. digit, and should only encompass that code.
  81.  
  82. Your routine cannot handle the largest negative integer (-32768 if 
  83. 16bit ints).  Even though it may *appear* to work, because adding 8 to 
  84. 32760 creates 0x8000, i.e. -32768, which remains the same if multiplied 
  85. by -1, it actually causes integer overflow, which will cause an 
  86. exception on some machines.
  87.  
  88. Nitpicking:
  89.  
  90.  The name of your parameter "change" is inappropriate.
  91.  
  92.  You shouldn't name your function the same as one in the library.
  93.  
  94.  The function demonstrates clearly that 8-character indents make
  95.  programs difficult to read (asbestos suit on).
  96.  
  97. Please don't take this criticism harshly, posting code will always lead 
  98. to nitpicking, and learning to handle all error conditions and 
  99. pathalogical cases comes with experience.  But remember - handling the 
  100. error conditions properly is just as important as handling the "real" 
  101. cases.
  102.  
  103. Here's my attempt.  Note that you need to include <ctype.h> for isspace 
  104. and isdigit, and that the routine crashes if string is NULL (as it does 
  105. on most systems unfortunately).  You can write your own code for 
  106. isspace and isdigit if you want this to be "all your own" code.
  107.  
  108. int new_atoi (char *string)
  109. {
  110.   int newint;
  111.   int negative;  /* really Boolean */
  112.  
  113.   /* step over whitespace */
  114.   while (isspace(*string))
  115.     string++;
  116.  
  117.   /* handle leading sign */
  118.   negative = (*string == '-');
  119.  
  120.   if (negative || *string == '+')
  121.     string++;
  122.  
  123.   /* step through the digits */
  124.   newint = 0;
  125.   while (isdigit(*string))
  126.   {
  127.     /* subtract '0' before adding/subtracting to ensure no
  128.        unnecessary overflow */
  129.     if (negative)
  130.       newint = newint * 10 - (*string - '0');
  131.     else
  132.       newint = newint * 10 + (*string - '0');
  133.  
  134.     string++;
  135.   }
  136.  
  137.   return(newint);
  138. }
  139.  
  140. Note that if written for a library where fastest execution possible is 
  141. important, it *might* be a good idea to avoid the unnecessary initial 
  142. multiplication of 0 by 10 , and the negative test could be brought 
  143. outside the loop, producing two loops, one for positive and one for 
  144. negative numbers. The only reason negative is handled separately from 
  145. positive is to avoid overflow on the pathalogical -32768 case.
  146. This would give:
  147.  
  148.   /* step through the digits */
  149.   newint = 0;
  150.   if (negative)
  151.   {
  152.     if (isdigit(*string))
  153.     {
  154.       newint = '0' - *string;
  155.       while (isdigit(*(++string)))
  156.         newint = newint * 10 - (*string - '0');
  157.     }
  158.   }
  159.   else
  160.   {
  161.     if (isdigit(*string))
  162.     {
  163.       newint = *string - '0';
  164.       while (isdigit(*(++string)))
  165.         newint = newint * 10 + (*string - '0');
  166.     }
  167.   }
  168.   return(newint);
  169.  
  170. Note also, that if you are writing your own version of atoi, it might 
  171. be nice to consider passing a pointer to a pointer as the argument.  
  172. This gives you the ability to return, in the argument, the address of 
  173. the first character past the end of the scanned integer - this often 
  174. avoids having to do strtok's or other nasties to get past the integer 
  175. you have just scanned.  (Its also nice also to have your own variations 
  176. of strcpy and strcat that return the address of the *end* of the 
  177. string, which you know at that stage - it often avoids having to do 
  178. subsequent strlen's).
  179. -- 
  180. Ray Dunn (opinions are my own) | Phone: (514) 938 9050
  181. Montreal                       | Phax : (514) 938 5225
  182. ray@ultimate-tech.com          | Home : (514) 630 3749
  183.  
  184.